package com.example.handpose_front.LearnAndReviewPage;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.util.Size;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;

import com.example.handpose_front.BaseActivity;
import com.example.handpose_front.R;
import com.example.handpose_front.dto.DataResponse;
import com.example.handpose_front.utils.BitmapUtils;
import com.example.handpose_front.utils.LocalStorage;
import com.example.handpose_front.utils.OKHttpUtil.GestureWebSocketClient;
import com.example.handpose_front.utils.OKHttpUtil.HttpUrl;
import com.example.handpose_front.utils.OKHttpUtil.OKHttpUtil;
import com.example.handpose_front.utils.OKHttpUtil.ResponseBody;
import com.google.common.util.concurrent.ListenableFuture;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;

public class LearnActivity extends BaseActivity implements View.OnClickListener {

    private GestureWebSocketClient gestureClient;

    // 响应体
    private DataResponse dataResponse;
    Map<String, String> map = new HashMap<>();

    // 显示内容
    private String letter_name = "";
    private String image_name = "";
    private String image_descripion = "";

    // next按钮, capture按钮
    private Button nextButton;
    private Button captureButton;
    // 当前学习词数、词典总词数
    private TextView curStudyingWords_tv;
    private TextView curDictionaryWords_tv;
    private TextView pointsShow_tv;
    // camera
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;

    // 记录当前词典id、词典总词数、手势id、手势id计数、
    public String curDictionaryId = LocalStorage.getLocalCurDictionaryId();
    public String userPhone = LocalStorage.getCurrentPhone();
    public String curDictionaryWords = "0";
    public Integer curStudiedWords_i = 0;
    public String curStudiedWords = "0";
    public Integer handposeId_i = 1;
    public String handposeId = "1";
    public Integer curStudyingWords_i = 1;
    public String curStudyingWords = "1";
    public String points_return = "";

    ImageAnalysis imageAnalysis;
    public Bitmap mutableBitmap;

    public Long startTime;
    public Long endTime;
    public Long stayTime;
    public Long stayMinutes;

    public String userStatusId;
    // 我的数据
    private String todayWords = LocalStorage.getTodayWords();
    private String totalWords = "0";
    private String todayTime = "0";
    private String totalTime = "0";
    private Integer todayWords_i = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_learn);

        // 获取页面开始时间
        startTime = SystemClock.elapsedRealtime();
        System.out.println("start time:" + startTime.toString());
        curStudyingWords_tv = findViewById(R.id.cur_studying_words);
        curDictionaryWords_tv = findViewById(R.id.dic_words);
        pointsShow_tv = findViewById(R.id.points_show_tv);
        sendGetHandDictionaryRequest(curDictionaryId);
        sendGetCurDictionaryRequest(userPhone);

        // 初始化WebSocket客户端（连接到Python手势识别服务）
        String wsUrl = HttpUrl.getWebsocketUrl();
        gestureClient = new GestureWebSocketClient(wsUrl);
        gestureClient.connect(new GestureWebSocketClient.GestureCallback() {
            @Override
            public void onResult(GestureWebSocketClient.GestureResult result) {
                runOnUiThread(() -> {
                    // 更新手势识别结果到UI
                    String resultText = String.format("%s (%.1f%%)",
                            result.gesture, result.confidence * 100);
                    pointsShow_tv.setText(resultText);

                    // 记录关键点
                    if (result.landmarks != null) {
                        points_return = Arrays.deepToString(result.landmarks);
                        Log.d("GesturePoints", points_return);
                    }
                });
            }

            @Override
            public void onError(String error) {
                runOnUiThread(() -> {
                    Toast.makeText(LearnActivity.this,
                            "手势识别错误: " + error, Toast.LENGTH_SHORT).show();
                });
            }
        });

        // 返回一个Future对象，表示相机的实例化可能会稍后完成
        checkCameraPermissions(this); // 检查相机权限
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        cameraProviderFuture.addListener(() -> {
            try {
                // 添加一个监听器
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                // 绑定预览
                bindPreview(cameraProvider);

                executeAnalysis();

            } catch (ExecutionException | InterruptedException e) {
                Log.e("CameraX", "初始化失败", e);
            }
        }, ContextCompat.getMainExecutor(this));
        sendHandposeRequest();
        initView();
        initEvent();
        sendSetWordsTimeRequest();
    }

    @Override
    protected void onPause() {
        super.onPause();
        //获取页面暂停时间
        endTime = SystemClock.elapsedRealtime();
        System.out.println("end time:" + endTime.toString());
        stayTime = endTime - startTime;
        stayMinutes = stayTime / (60 * 1000); // 将毫秒转换为分钟
        sendSetWordsTimeRequest();
    }

    private void initEvent() {
        nextButton.setOnClickListener(this);
        captureButton.setOnClickListener(this);
    }

    private void initView() {
        letter_name = dataResponse.getData().get("handposeName").toString();
        image_name = dataResponse.getData().get("handposePicture").toString();
        image_descripion = dataResponse.getData().get("handposeDescription").toString();
        initImage();
        initTextView();
        initImageDescription();
        nextButton = findViewById(R.id.next_btn);
        captureButton = findViewById(R.id.capture_btn);
    }

    private boolean sendSetWordsTimeRequest() {
        map.clear();

        map.put("userPhone", userPhone);
        String response = OKHttpUtil.postSyncRequest(HttpUrl.getBaseUrl(), map, "user", "user_info");
        dataResponse = ResponseBody.getResponseBody(response);

        if (dataResponse.getCode().equals("200")) {
            userStatusId = dataResponse.getData().get("userStatusId").toString();
            sendGetWordsRequest();
            // 设置Words与Time
            map.clear();

            map.put("userStatusId" ,userStatusId);
            map.put("totalWords", totalWords);
//            map.put("totalTime", stayMinutes.toString());

            String response1 = OKHttpUtil.postSyncRequest(HttpUrl.getBaseUrl(), map, "userStatus", "set_words_time");
            dataResponse = ResponseBody.getResponseBody(response1);

            if (dataResponse.getCode().equals("200")) {

                return true;
            } else {
                // 提示错误信息
                Toast.makeText(this, "操作失败", Toast.LENGTH_SHORT).show();
                return false;
            }
        } else {
            // 提示错误信息
            Toast.makeText(this, "操作失败", Toast.LENGTH_SHORT).show();
            return false;
        }
    }

    private boolean sendGetWordsRequest() {
        map.clear();

        map.put("userPhone", userPhone);
        String response = OKHttpUtil.postSyncRequest(HttpUrl.getBaseUrl(), map, "curDictionary", "get_totalwords");
        dataResponse = ResponseBody.getResponseBody(response);
        if (dataResponse.getCode().equals("200")) {
            totalWords = dataResponse.getData().get("totalWords").toString();
            return true;
        } else {
            // 提示错误信息
            Toast.makeText(this, "操作失败", Toast.LENGTH_SHORT).show();
            return false;
        }
    }

    private void sendHandposeRequest() {
        // 向后端发起请求
        map.clear();

        map.put("handDictionaryId", curDictionaryId);
        map.put("handposeId", handposeId);

        String response = OKHttpUtil.postSyncRequest(HttpUrl.getBaseUrl(), map, "handpose");
        dataResponse = ResponseBody.getResponseBody(response);
    }

    public boolean sendGetHandDictionaryRequest(String handDictionaryId) {
        map.clear();

        map.put("handDictionaryId", handDictionaryId);
        String response = OKHttpUtil.postSyncRequest(HttpUrl.getBaseUrl(), map, "handDictionary", "get_dic");
        dataResponse = ResponseBody.getResponseBody(response);
        if (dataResponse.getCode().equals("200")) {
            curDictionaryWords = dataResponse.getData().get("handDictionaryWords").toString();
            curDictionaryWords_tv.setText(curDictionaryWords);
            // 获取词典信息
            return true;
        } else {
            // 提示错误信息
            Toast.makeText(this, "操作失败", Toast.LENGTH_SHORT).show();
            return false;
        }
    }

    public boolean sendGetCurDictionaryRequest(String userPhone) {
        map.clear();

        map.put("userPhone", userPhone);
        String response = OKHttpUtil.postSyncRequest(HttpUrl.getBaseUrl(), map, "curDictionary", "get_cur");
        dataResponse = ResponseBody.getResponseBody(response);
        if (dataResponse.getCode().equals("200")) {
            curStudiedWords = dataResponse.getData().get("curStudiedWords").toString();
            handposeId = curStudiedWords2handposeId(curStudiedWords);
            // 这里要置为正在学习的（+1
            curStudyingWords_i = Integer.parseInt(curStudiedWords) + 1;
            curStudyingWords = String.valueOf(curStudyingWords_i);
            curStudyingWords_tv.setText(curStudyingWords);
            sendUpdateCurStudiedWords(curStudiedWords);
            // 获取词典成功
            return true;
        } else {
            // 提示错误信息
            Toast.makeText(this, "操作失败", Toast.LENGTH_SHORT).show();
            return false;
        }
    }

    public boolean sendUpdateCurStudiedWords(String curStudiedWords) {
        map.clear();

        map.put("curDictionaryId", curDictionaryId);
        map.put("userPhone", userPhone);
        map.put("curStudiedWords", curStudiedWords);
        String response = OKHttpUtil.postSyncRequest(HttpUrl.getBaseUrl(), map, "curDictionary", "update_cur");
        dataResponse = ResponseBody.getResponseBody(response);
        if (dataResponse.getCode().equals("200")) {
            curStudiedWords = dataResponse.getData().get("curStudiedWords").toString();
            Log.d("curStudiedWords:", curStudiedWords);
            // 获取词典成功
            return true;
        } else {
            // 提示错误信息
            Toast.makeText(this, "操作失败", Toast.LENGTH_SHORT).show();
            return false;
        }

    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onClick(View v) {
        if (v.getId() == nextButton.getId()) {

            // bug记录：这里请求drawable下图片的名称不能带后缀名！！
            // 只传图片名称就可以，Android解析bitmap忽略.jpg

            ApplicationInfo appInfo = getApplicationInfo();
            int resID = getResources().getIdentifier("er", "drawable", appInfo.packageName);
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resID);
            String s = convertImageToString(bitmap);

            // TODO: 2024/3/5   线程不安全处理
            curStudiedWords_i = Integer.parseInt(curStudiedWords);
            curStudiedWords_i++;
            curStudiedWords = String.valueOf(curStudiedWords_i);

            handposeId = curStudiedWords2handposeId(curStudiedWords);
            Log.d("handposeId", handposeId);

            // 这里需要sendRequest + initView，因为每次下一个都需要发查询请求！
            // 更新curStudiedWords
            // 这里要置为正在学习的（+1
            curStudyingWords_i = Integer.parseInt(curStudiedWords) + 1;
            curStudyingWords = String.valueOf(curStudyingWords_i);
            curStudyingWords_tv.setText(curStudyingWords);
            sendUpdateCurStudiedWords(curStudiedWords);

            // 更新todayWords,totalWords已经随着
            todayWords_i = Integer.parseInt(todayWords) + 1;
            todayWords = String.valueOf(todayWords_i);
            LocalStorage.setTodayWords(todayWords);

            // 更新handposeId
            handposeId = curStudiedWords2handposeId(curStudiedWords);
            sendHandposeRequest();
            initView();
        }
        if (v.getId() == captureButton.getId()) {
            
        }
    }

    private void initImage() {

        // bug记录：这里请求drawable下图片的名称不能带后缀名！！
        // 只传图片名称就可以，Android解析bitmap忽略.jpg

        ImageView imageView = findViewById(R.id.image_view);
        ApplicationInfo appInfo = getApplicationInfo();
        int resID = getResources().getIdentifier(image_name, "drawable", appInfo.packageName);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resID);
        imageView.setImageBitmap(bitmap);

    }

    // 绑定Preview
    void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
        Preview preview = new Preview.Builder()
                .build();

        // 选择前置摄像头
        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
                .build();
        PreviewView previewView = findViewById(R.id.previewView);
        preview.setSurfaceProvider(previewView.getSurfaceProvider());

        imageAnalysis = new ImageAnalysis.Builder()
                .setTargetResolution(new Size(1280, 720))
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build();

        Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview, imageAnalysis);
    }

    // 获取相机权限
    public static void checkCameraPermissions(Context context){
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED)
        {
            // Permission is not granted
            Log.d("checkCameraPermissions", "No Camera Permissions");
            ActivityCompat.requestPermissions((Activity) context,
                    new String[] { Manifest.permission.CAMERA },
                    100);
        }
    }

    private void executeAnalysis() {
        ImageAnalysis.Analyzer analyzer = new ImageAnalysis.Analyzer() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void analyze(@NonNull ImageProxy imageProxy) {

                int width = imageProxy.getWidth();
                int height = imageProxy.getHeight();
                int format = imageProxy.getFormat();

                System.out.println("width");
                System.out.println(width);
                System.out.println("height");
                System.out.println(height);
                // 输出35为YUV_420_888(CameraX输出)
                Log.d("TAG", "Image width: " + width + ", height: " + height + ", format: " + format);

                // 优先使用WebSocket发送, WebSocket不可用时降级到OkHttp
                if (gestureClient.isConnected()) {
                    gestureClient.sendImageFrame(imageProxy);
                } else {

                    // 将YUV_420_888转为BitMap
                    @SuppressLint("UnsafeOptInUsageError") Bitmap bitmap = BitmapUtils.getBitmap(imageProxy);
                    String base_image = convertImageToString(bitmap);
                    System.out.println(base_image);

                    // 向后端发起请求
                    Map<String, String> map = new HashMap<>();
                    map.put("base_image", base_image);

                    String response = OKHttpUtil.postSyncRequest(HttpUrl.getAlgorithmUrl(), map, "algorithm", "inference");
                    dataResponse = ResponseBody.getResponseBody(response);

                    points_return = dataResponse.getData().get("points").toString();

                    System.out.println("points_return!!!!!!!");
                    System.out.println(points_return);

                    LearnActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // 在 UI 线程中执行操作
                            pointsShow_tv.setText(points_return);
                        }
                    });

                }
                // 释放图像资源
                imageProxy.close();
            }
        };
        // 使用单独的线程来分析
        imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), analyzer);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 清理资源
        if (gestureClient != null) {
            gestureClient.disconnect();
        }
        if (cameraProviderFuture != null) {
            cameraProviderFuture.cancel(true);
        }
    }

    private void initTextView() {
        TextView letterName = (TextView) findViewById(R.id.letter_name);
        letterName.setText(letter_name);
    }

    private void initImageDescription() {
        TextView imageDescription = (TextView) findViewById(R.id.image_descripion);
        imageDescription.setText(image_descripion);
    }

    private String curStudiedWords2handposeId(String curStudiedWords) {
        if (curDictionaryId.equals("1")) {
            handposeId_i = Integer.parseInt(curStudiedWords) + 1;
            handposeId = String.valueOf(handposeId_i);
        }
        if (curDictionaryId.equals("2")) {
            handposeId_i = Integer.parseInt(curStudiedWords) + 31;
            handposeId = String.valueOf(handposeId_i);
        }
        if (curDictionaryId.equals("3")) {
            handposeId_i = Integer.parseInt(curStudiedWords) + 57;
            handposeId = String.valueOf(handposeId_i);
        }
        return handposeId;
    }

    /**
     * 图片bitmap转成base64数据
     *
     * @param bitmap
     * @return
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static String convertImageToString(Bitmap bitmap) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();// outputstream
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        byte[] appicon = baos.toByteArray();// 转为byte数组
        String bitString = Base64.getEncoder().encodeToString(appicon);
//        System.out.println(bitString);
        return bitString;
    }


    /**
     * Base64转Bitmap
     *
     * @param base64String
     * @return Bitmap 图片
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private static Bitmap base642Bitmap(String base64String) throws IOException {
        if (null == base64String) throw new NullPointerException();
        byte[] decodedBytes = Base64.getDecoder().decode(base64String);
        ByteArrayInputStream bais = new ByteArrayInputStream(decodedBytes);
        bais.read(decodedBytes);

        YuvImage yuvimage=new YuvImage(decodedBytes, ImageFormat.NV21, 20,20, null);//20、20分别是图的宽度与高度
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        yuvimage.compressToJpeg(new Rect(0, 0,20, 20), 80, baos);//80--JPG图片的质量[0-100],100最高
        byte[] jdata = baos.toByteArray();

        Bitmap mBitmap = BitmapFactory.decodeByteArray(jdata, 0, jdata.length);
        return mBitmap;
    }


}